﻿// Copyright (c) 2007-2021 西安交通信息投资营运有限公司 版权所有
// 作者:吕艳阳

using System;
using DevExpress.XtraDataLayout;
using DevExpress.XtraLayout;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Threading.Tasks;
using DevExpress.Utils.Design;
using XCI.Core;
using XCI.Setting;
using XCI.Helper;

namespace XCI.Windows
{
    [ToolboxBitmap(typeof(LayoutControl), "Images.datalayoutcontrol.bmp")]
    [System.ComponentModel.DesignerCategory("Code")]
    public class DataLayoutControlPlus : DataLayoutControl, ISettingSerializer
    {
        private LoadingMask _loadPanel;

        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public LoadingMask LoadPanel => _loadPanel ?? (_loadPanel = new LoadingMask(this));

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public SettingStoreManager SettingManager { get; set; }

        /// <summary>
        /// 配置标识
        /// </summary>
        [Category("XCI"), Description("配置标识")]
        [SmartTagProperty("配置标识", "XCI", SmartTagActionType.RefreshAfterExecute)]
        public virtual string Id { get; set; } = $"layout-{StringHelper.Guid()}";

        /// <summary>
        /// 允许自定义配置
        /// </summary>
        [Category("XCI"), Description("允许自定义配置"), DefaultValue(true)]
        [SmartTagProperty("允许自定义配置", "XCI", SmartTagActionType.RefreshAfterExecute)]
        public bool AllowCustomSetting { get; set; } = true;

        [Category("XCI"), Description("自动加载配置"), DefaultValue(true)]
        [SmartTagProperty("自动加载配置", "XCI", SmartTagActionType.RefreshAfterExecute)]
        public bool AutoLoadSetting { get; set; } = true;

        [Category("XCI"), Description("加载配置之前事件")]
        public event EventHandler<EventArgs> BeforeRestoreLayout;

        [Category("XCI"), Description("加载配置之后事件")]
        public event EventHandler<EventArgs> AfterRestoreLayout;

        [Category("XCI"), Description("控件开始初始化事件")]
        public event EventHandler<EventArgs> BeforeInitialize;
        [Category("XCI"), Description("控件初始化结束事件")]
        public event EventHandler<EventArgs> AfterInitialize;

        protected virtual void OnBeforeInitialize()
        {
            BeforeInitialize?.Invoke(this, EventArgs.Empty);
        }

        protected virtual void OnAfterInitialize()
        {
            AfterInitialize?.Invoke(this, EventArgs.Empty);
        }

        public DataLayoutControlPlus()
        {
            if (WinFormHelper.IsDesignMode())
            {
                this.OptionsCustomizationForm.DefaultPage = CustomizationPage.LayoutTreeView;
                this.OptionsCustomizationForm.ShowPropertyGrid = true;
                this.OptionsSerialization.RestoreAppearanceTabPage = true;
                this.OptionsSerialization.RestoreAppearanceItemCaption = true;
                this.OptionsSerialization.RestoreTextToControlDistance = true;
                this.CustomizationMode = CustomizationModes.Default;
            }
        }

        protected override async void OnCreateControl()
        {
            base.OnCreateControl();
            if (WinFormHelper.IsDesignMode()) return;
            OnBeforeInitialize();
            this.AllowCustomization = AllowCustomSetting && AppDefaultSettings.AllowCustomLayoutControlSetting;
            RegisterUserCustomizationForm(typeof(FrmSettingLayoutForm));
            SettingManager = new SettingStoreManager(this, Id);

            if (AutoLoadSetting)
            {
                if (!string.IsNullOrEmpty(Id))
                {
                    BeforeRestoreLayout?.Invoke(this, EventArgs.Empty);
                    await SettingManager.LoadCurrentAsync();
                    AfterRestoreLayout?.Invoke(this, EventArgs.Empty);
                }
                else
                {
                    Debug.WriteLine("请指定有效的DataLayoutPlusControl-Id");
                }
            }

            OnAfterInitialize();
        }

        /// <summary>
        /// 循环容器中的所有控件及所有子孙控件
        /// </summary>
        /// <param name="callback">每个控件回调函数</param>
        public void ForEachControl(Action<object> callback)
        {
            App.ContainerData.ForEach(this, callback);
        }

        /// <summary>
        /// 清除容器中的所有控件及所有子孙控件的值
        /// </summary>
        public void ClearModel()
        {
            App.ContainerData.ClearModel(this);
        }

        /// <summary>
        /// 获取容器中的所有控件及所有子孙控件的值并绑定到指定对象中
        /// </summary>
        /// <param name="model">绑定对象</param>
        public object GetModel(object model)
        {
            App.ContainerData.GetModel(this, model);
            return model;
        }

        /// <summary>
        /// 把指定对象中属性并绑定到容器中的所有控件及所有子孙控件上
        /// </summary>
        /// <param name="model">绑定对象</param>
        public void SetModel(object model)
        {
            App.ContainerData.SetModel(this, model);
        }

        /// <summary>
        /// 异步绑定表单数据
        /// </summary>
        /// <returns>等待的任务</returns>
        public Task BindingDataAsync()
        {
            return App.ContainerData.BindingDataAsync(this);
        }
        
        /// <summary>
        /// 异步绑定控件EditValue
        /// </summary>
        /// <returns>等待的任务</returns>
        public Task BindingEditValueAsync()
        {
            return App.ContainerData.BindingEditValueAsync(this);
        }

        /// <summary>
        /// 验证对象并处理错误
        /// </summary>
        /// <param name="obj">待验证的对象</param>
        /// <returns>验证通过返回true,否则返回false</returns>
        public bool ValidateModel(object obj)
        {
            return App.Validator.ValidateObject(obj);
        }

        #region Implementation of ISettingSerializer

        /// <summary>
        /// 加载配置到控件
        /// </summary>
        /// <param name="xmlFile">xml文件路径</param>
        public void RestoreLayout(string xmlFile)
        {
            RestoreLayoutFromXml(xmlFile);
        }

        /// <summary>
        /// 保存控件配置
        /// </summary>
        /// <param name="xmlFile">xml文件路径</param>
        public void SaveLayout(string xmlFile)
        {
            SaveLayoutToXml(xmlFile);
        }

        #endregion
    }
}